﻿// Copyright (c) Inossem. All rights reserved.
// Licensed under the LGPL-3.0 license. See LICENSE file in the project root for full license information.
using DWF.Studio.Host.RemoteHandler;
using DWF.Studio.ISerivces;
using DWF.Studio.Models;
using DWF.Studio.Models.Enum;
using DWF.Studio.Project;
using DWF.Studio.RemoteCtrls;
using DWF.Studio.RemoteCtrls.Proxy;
using DWF.Studio.RemoteCtrls.Models;
using DWF.Studio.ScriptEngine.IPC.WorkFlow;
using DWF.Studio.Services;
using System;
using System.AddIn.Pipeline;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using WpfMessageBoxLibrary;

namespace DWF.Studio.Host
{
    /// <summary>
    /// 远程设计器本地宿主类
    /// </summary>
    internal class RemoteDesignerHost : IDisposable
    {
        /// <summary>
        /// 设计器模型改变事件
        /// </summary>
        public Action<EventArgs> DesignModelChanged;

        /// <summary>
        /// 设计器模型改变事件
        /// </summary>
        public Action<BreakpointEventArgs> BreakpointChanged;
        /// <summary>
        /// 自变量改变
        /// </summary>
        public Action<DWF.Studio.Script.ArgumentEventArgs> PropertyModelChanged;

        /// <summary>
        /// 设计器代理类
        /// </summary>
        private ActivityDesignerProxy _ctrlDesignerProxy = null;

        /// <summary>
        /// 活动设计器view
        /// </summary>
        private FrameworkElement _designerView = null;

        /// <summary>
        /// 属性栏view
        /// </summary>
        private FrameworkElement _propertiesView = null;

        /// <summary>
        /// 概要view
        /// </summary>
        private FrameworkElement _outlineView = null;

        /// <summary>
        /// 活动通知处理
        /// </summary>
        private ActivityNoticeHandler _noticeHandler = null;

        /// <summary>
        /// 设计模型变更处理
        /// </summary>
        private GenericHandler<EventArgs> _modelChangedHandler = null;

        private GenericHandler<BreakpointEventArgs> _breakpointChanged = null;
        private GenericHandler<ArgumentEventArgs> _propertyModelChanged = null;

        private IActivityNoticeService _activityNoticeService = null;

        /// <summary>
        /// 当前编辑的工作流脚本
        /// </summary>
        public string CurrentScript
        {
            get
            {
                return this._ctrlDesignerProxy.GetXaml();
            }
        }

        public bool IsSnippetScript
        {
            get;
            private set;
        }

        public RemoteDesignerHost(ActivityDesignerProxy designer, bool isSnippet = false)
        {
            IsSnippetScript = isSnippet;

            _activityNoticeService = new ActivityNoticeService();

            this._ctrlDesignerProxy = designer;
            _noticeHandler = new ActivityNoticeHandler();
            _noticeHandler.SetAction(this.notice);
            this._ctrlDesignerProxy.ActivityNotice = _noticeHandler.Action;

            _modelChangedHandler = new GenericHandler<EventArgs>();
            _modelChangedHandler.SetAction((e) =>
            {
                if (DesignModelChanged != null)
                {
                    DesignModelChanged(e);
                }
            });
            this._ctrlDesignerProxy.DesignModelChanged = _modelChangedHandler.Action;

            if (!IsSnippetScript)
            {
                _breakpointChanged = new GenericHandler<BreakpointEventArgs>();
                _breakpointChanged.SetAction((e) =>
                {
                    if (BreakpointChanged != null)
                    {
                        BreakpointChanged(e);
                    }
                });

                this._ctrlDesignerProxy.BreakpointChanged = _breakpointChanged.Action;
            }
            _propertyModelChanged = new GenericHandler<ArgumentEventArgs>();
            _propertyModelChanged.SetAction((e) =>
            {
                if (PropertyModelChanged != null)
                {
                    List<Models.ProjectParam> projectParams = new List<Models.ProjectParam>();
                    foreach (var item in e.Arguments)
                    {
                        var itemType = new Models.Enum.EProjectParamType();
                        switch (item.ParamType)
                        {
                            case RemoteCtrls.Models.EProjectParamType.Number: itemType = Models.Enum.EProjectParamType.Number; break;
                            case RemoteCtrls.Models.EProjectParamType.Boolean: itemType = Models.Enum.EProjectParamType.Boolean; break;
                            case RemoteCtrls.Models.EProjectParamType.String: itemType = Models.Enum.EProjectParamType.String; break;
                            case RemoteCtrls.Models.EProjectParamType.File: itemType = Models.Enum.EProjectParamType.File; break;
                        }
                        projectParams.Add(new Models.ProjectParam()
                        {
                            Name = item.Name,
                            Value = item.Value,
                            Description = item.Description,
                            ParamType = itemType
                        });
                    }
                    PropertyModelChanged(new DWF.Studio.Script.ArgumentEventArgs(projectParams));
                }
            });
            this._ctrlDesignerProxy.PropertyModelChanged = _propertyModelChanged.Action;
        }

        /// <summary>
        /// 获取工作流设计view
        /// </summary>
        /// <returns></returns>
        public FrameworkElement GetDesignerView()
        {
            if (_designerView == null)
            {
                _designerView = FrameworkElementAdapters.ContractToViewAdapter(_ctrlDesignerProxy.GetDesignerView());
            }

            return _designerView;
        }

        /// <summary>
        /// 获取属性栏view
        /// </summary>
        /// <returns></returns>
        public FrameworkElement GetPropertiesView()
        {
            if (_propertiesView == null)
            {
                _propertiesView = FrameworkElementAdapters.ContractToViewAdapter(_ctrlDesignerProxy.GetPropertiesView());
            }

            return _propertiesView;
        }
 
        /// <summary>
        /// 获取概要栏view
        /// </summary>
        /// <returns></returns>
        public FrameworkElement GetOutlineView()
        {
            if (_outlineView == null)
            {
                _outlineView = FrameworkElementAdapters.ContractToViewAdapter(_ctrlDesignerProxy.GetOutlineView());
            }

            return _outlineView;
        }

        /// <summary>
        /// 刷新设计器
        /// </summary>
        public void Flush()
        {
            this._ctrlDesignerProxy.Flush();
        }

        /// <summary>
        /// 加载脚本
        /// </summary>
        /// <param name="fileName"></param>
        public void Load(string fileName)
        {
            this._ctrlDesignerProxy.Load(fileName);
        }

        public void Load(string fileName, List<BreakpointInfo> breakpoints)
        {
            if (breakpoints == null)
            {
                this._ctrlDesignerProxy.Load(fileName);
            }
            else
            {
                this._ctrlDesignerProxy.Load(fileName, breakpoints);
            }
        }

        /// <summary>
        /// 加载脚本
        /// </summary>
        public void Load()
        {
            this._ctrlDesignerProxy.Load();
        }

        /// <summary>
        /// 保存脚本
        /// </summary>
        /// <param name="fileName"></param>
        public void Save(string fileName)
        {
            this._ctrlDesignerProxy.Save(fileName);
        }

        public IEnumerable<ValidationInfo> Validate()
        {
            return this._ctrlDesignerProxy.Validate();
        }

        public void SetReadOnly(bool isReadOnly)
        {
            this._ctrlDesignerProxy.SetReadOnly(isReadOnly);
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            this._ctrlDesignerProxy?.Dispose();
            this._noticeHandler?.Dispose();
            this._noticeHandler = null;
            this._modelChangedHandler?.Dispose();
            this._modelChangedHandler = null;
            this._breakpointChanged?.Dispose();
            this._breakpointChanged = null;
            this._noticeHandler?.Dispose();
            this._noticeHandler = null;
            this._propertyModelChanged?.Dispose();
            this._propertyModelChanged = null;
            this._activityNoticeService = null;
        }

        public string GetRootActivityTypeName()
        {
            return _ctrlDesignerProxy.GetRootActivityTypeName();
        }

        public string GetRootActivityCode()
        {
            return _ctrlDesignerProxy.GetRootActivityCode();
        }

        public void SetActivityByCode(string activityCode, IDictionary<string, object> param)
        {
            _ctrlDesignerProxy.SetActivityByCode(activityCode, param);
        }
        public void SetChangeArgument(List<Models.ProjectParam> projectParams)
        {
            List<RemoteCtrls.Models.ProjectParam> ppms = new List<RemoteCtrls.Models.ProjectParam>();
            foreach (var projectParam in projectParams)
            {
                RemoteCtrls.Models.ProjectParam ppm = new RemoteCtrls.Models.ProjectParam()
                {
                    Name = projectParam.Name,
                    Value = projectParam.Value,
                    Description = projectParam.Description,
                    InOrOut=projectParam.InOrOut
                };
                switch (projectParam.ParamType)
                {
                    case Models.Enum.EProjectParamType.Number: ppm.ParamType = RemoteCtrls.Models.EProjectParamType.Number; break;
                    case Models.Enum.EProjectParamType.Boolean: ppm.ParamType = RemoteCtrls.Models.EProjectParamType.Boolean; break;
                    case Models.Enum.EProjectParamType.String: ppm.ParamType = RemoteCtrls.Models.EProjectParamType.String; break;
                    case Models.Enum.EProjectParamType.File: ppm.ParamType = RemoteCtrls.Models.EProjectParamType.File; break;
                }
                ppms.Add(ppm);
            }
            
            _ctrlDesignerProxy.SetChangeArgument(ppms);
        }
        
        public void SetInArgument(Models.ProjectParam projectParam)
        {
            RemoteCtrls.Models.ProjectParam ppm = new RemoteCtrls.Models.ProjectParam() {
                Name = projectParam.Name,
                Value = projectParam.Value,
                Description = projectParam.Description,
            };
            switch (projectParam.ParamType)
            {
                case Models.Enum.EProjectParamType.Number:ppm.ParamType = RemoteCtrls.Models.EProjectParamType.Number; break;
                case Models.Enum.EProjectParamType.Boolean:ppm.ParamType = RemoteCtrls.Models.EProjectParamType.Boolean; break;
                case Models.Enum.EProjectParamType.String:ppm.ParamType = RemoteCtrls.Models.EProjectParamType.String; break;
                case Models.Enum.EProjectParamType.File:ppm.ParamType = RemoteCtrls.Models.EProjectParamType.File; break;
            }
            _ctrlDesignerProxy.SetInArgument(ppm);
        }

        public void SetOutArgument(Models.ProjectParam projectParam)
        {
            RemoteCtrls.Models.ProjectParam ppm = new RemoteCtrls.Models.ProjectParam()
            {
                Name = projectParam.Name,
                Value = projectParam.Value,
                Description = projectParam.Description,
            };
            
            switch (projectParam.ParamType)
            {
                case Models.Enum.EProjectParamType.Number: ppm.ParamType = RemoteCtrls.Models.EProjectParamType.Number; break;
                case Models.Enum.EProjectParamType.Boolean: ppm.ParamType = RemoteCtrls.Models.EProjectParamType.Boolean; break;
                case Models.Enum.EProjectParamType.String: ppm.ParamType = RemoteCtrls.Models.EProjectParamType.String; break;
                case Models.Enum.EProjectParamType.File: ppm.ParamType = RemoteCtrls.Models.EProjectParamType.File; break;
            }
            _ctrlDesignerProxy.SetOutArgument(ppm);
        }

        /// <summary>
        /// 添加活动
        /// </summary>
        /// <param name="parentCode"></param>
        /// <param name="activityTypeName"></param>
        /// <param name="param"></param>
        public string AddActivityByParentCode(string parentCode, string activityTypeName, IDictionary<string, object> param)//在设计器中添加活动 不可删除
        {
            return _ctrlDesignerProxy.AddActivityByParentCode(parentCode, activityTypeName, param);
        }

        public void InvokeCutCommand()
        {
            _ctrlDesignerProxy.CutCommand();
        }

        public void InvokeCopyCommand()
        {
            _ctrlDesignerProxy.CopyCommand();
        }

        public void InvokePasteCommand()
        {
            _ctrlDesignerProxy.PasteCommand();
        }

        public void InvokeUndoCommand()
        {
            _ctrlDesignerProxy.UndoCommand();
        }

        public void InvokeRedoCommand()
        {
            _ctrlDesignerProxy.RedoCommand();
        }

        public void DebugStart()
        {
            _ctrlDesignerProxy.DebugStart();
        }

        public void DebugEnd()
        {
            _ctrlDesignerProxy.DebugEnd();
        }

        public void ToggleBreakPoint()
        {
            _ctrlDesignerProxy.ToggleBreakPoint();
        }
        
        public void EnableBreakPoint(IEnumerable<Breakpoint> breakpoints)
        {
            List<BreakpointInfo> breakpointInfos = new List<BreakpointInfo>();
            foreach (Breakpoint breakpoint in breakpoints)
            {
                EBreakpointType eBreakpointType = new EBreakpointType();
                switch (breakpoint.BreakpointType)
                {
                    case 1:eBreakpointType = EBreakpointType.Enabled;break;
                    case 2: eBreakpointType = EBreakpointType.Bounded; break;
                }
                breakpointInfos.Add(new BreakpointInfo(breakpoint.ActivityId, breakpoint.ActivityName, breakpoint.ActivityType, eBreakpointType, breakpoint.Path,breakpoint.RefId));
            }
            _ctrlDesignerProxy.EnableBreakPoint(breakpointInfos);
        }
        public void BoundedBreakPoint(IEnumerable<Breakpoint> breakpoints)
        {
            List<BreakpointInfo> breakpointInfos = new List<BreakpointInfo>();
            foreach (Breakpoint breakpoint in breakpoints)
            {
                EBreakpointType eBreakpointType = new EBreakpointType();
                switch (breakpoint.BreakpointType)
                {
                    case 1: eBreakpointType = EBreakpointType.Enabled; break;
                    case 2: eBreakpointType = EBreakpointType.Bounded; break;
                }
                breakpointInfos.Add(new BreakpointInfo(breakpoint.ActivityId, breakpoint.ActivityName, breakpoint.ActivityType, eBreakpointType,breakpoint.Path, breakpoint.RefId));
            }
            _ctrlDesignerProxy.BoundedBreakPoint(breakpointInfos);
        }
        
        public void DeleteBreakPoint(Breakpoint breakpoint)
        {
            _ctrlDesignerProxy.DeleteBreakPoint(new BreakpointInfo(breakpoint.ActivityId, breakpoint.ActivityName, breakpoint.ActivityType, EBreakpointType.Bounded, breakpoint.Path, breakpoint.RefId));
        }
        public void DeleteAllBreakPoints()
        {
            _ctrlDesignerProxy.DeleteAllBreakPoints();
        }
        public bool Debug(string activityId)
        {
            return _ctrlDesignerProxy.Debug(activityId);
        }

        public bool DebugByStep(string activityId)
        {
            return _ctrlDesignerProxy.DebugByStep(activityId);
        }

        public void SelectActivityById(string activityId)
        {
            _ctrlDesignerProxy.LocateActivityById(activityId);
        }
        public void ActivitySelectionById(string activityId)
        {
            _ctrlDesignerProxy.ActivitySelectionById(activityId);
        }
        public void SelectActivityByIdRef(string activityIdRef)
        {
            _ctrlDesignerProxy.SetActivitySelectioniByIdRef(activityIdRef);
        }

        public IEnumerable<BreakpointInfo> GetBreakpoints()
        {
            return _ctrlDesignerProxy.GetBreakpoints();
        }

        public void ClearCurrentLocation()
        {
            _ctrlDesignerProxy.ClearCurrentLocation();
        }

        /// <summary>
        /// 处理通知
        /// </summary>
        /// <param name="msg"></param>
        private void notice(string msg, string data)
        {
            _activityNoticeService.ActivityNotice(msg, data);
        }
        public void Notes()
        {
            _ctrlDesignerProxy.Notes();
        }
        public void CancelNotes()
        {
            _ctrlDesignerProxy.CancelNotes();
        }
    }
}
